package com.leetao.sms.core.support.sender.impl.tencent;

import com.leetao.sms.core.constant.SmsExceptionEnums;
import com.leetao.sms.core.domain.Recipients;
import com.leetao.sms.core.domain.SmsParams;
import com.leetao.sms.core.domain.SmsResult;
import com.leetao.sms.core.domain.TemplateSms;
import com.leetao.sms.core.exception.SmsException;
import com.leetao.sms.core.support.sender.SmsSender;
import com.leetao.sms.core.support.sender.impl.tencent.config.TencentSmsProperties;
import com.leetao.sms.core.support.sender.impl.tencent.support.TencentSmsClientBuilder;
import com.leetao.sms.core.util.GsonUtils;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 腾讯短信发送器
 *
 * @author 菅江晖
 * @date 2021/6/7 - 16:26
 */
public class TencentSmsSender implements SmsSender {
    private static final Logger LOG = LoggerFactory.getLogger(TencentSmsSender.class);
    private static final String SEND_SUCCESSFUL_TAG = "Ok";

    private final TencentSmsProperties properties;
    private final SmsClient tencentClient;

    public TencentSmsSender(TencentSmsProperties properties) {
        this.properties = properties;
        this.tencentClient = TencentSmsClientBuilder
                .create(properties.getSecretId(), properties.getSecretKey())
                .region(properties.getRegion())
                .build();
    }

    @Override
    public Function<SmsParams, String[]> convertAvailableSmsParameters() {
        return smsParams -> smsParams.values().stream().map(Object::toString).toArray(String[]::new);
    }

    @Override
    public SmsResult sendSmsByTemplate(TemplateSms templateSms) throws SmsException {
        String templateId = templateSms.getTemplateId();
        SmsParams smsParams = templateSms.getSmsParams();
        Recipients recipients = templateSms.getRecipients();

        SendSmsRequest req = new SendSmsRequest();
        req.setPhoneNumberSet(recipients.toArray(new String[0]));
        req.setSmsSdkAppId(properties.getSmsSdkAppId());
        req.setSignName(properties.getSignName());
        req.setTemplateId(templateId);
        req.setTemplateParamSet(convertAvailableSmsParameters().apply(smsParams));
        SendSmsResponse resp;
        try {
            resp = tencentClient.SendSms(req);
        } catch (TencentCloudSDKException e) {
            throw SmsException.because(e.getMessage());
        }

        LOG.trace("tencent sms response:{}", GsonUtils.toJson(resp));
        TencentSmsRsp tencentSmsRsp = returnCustomTencentRsp(resp);
        return SmsResult.create(tencentSmsRsp.isHasSuccessful(), tencentSmsRsp).setMessage(tencentSmsRsp.getMessage());
    }


    @Override
    public SmsResult sendSms(Recipients recipients, String context) throws SmsException {
        throw SmsException.because(SmsExceptionEnums.NOT_SUPPORT);
    }

    /**
     * 返回自定义腾讯结果(总数,成功数)
     *
     * @param resp resp
     * @return TencentSmsRsp
     */
    private TencentSmsRsp returnCustomTencentRsp(SendSmsResponse resp) {
        TencentSmsRsp rsp = new TencentSmsRsp();
        SendStatus[] sendStatusSet = resp.getSendStatusSet();

        // 处理未发送成功的消息
        List<FailSmsRsp> collect = Arrays.stream(sendStatusSet)
                .filter(sendStatus -> !SEND_SUCCESSFUL_TAG.equals(sendStatus.getCode()))
                .map(sendStatus -> new FailSmsRsp(sendStatus.getMessage(), sendStatus.getPhoneNumber())).collect(Collectors.toList());

        rsp.setTotal(sendStatusSet.length);
        rsp.setFailNum(collect.size());
        rsp.setHasSuccessful(rsp.failNum < rsp.total);
        rsp.setMessage(rsp.failNum == 0 ? "all success" : "fail sms: " + GsonUtils.toJson(collect));
        rsp.setSource(resp);

        return rsp;
    }

    public static class FailSmsRsp {
        String message;
        String phoneNumber;

        public FailSmsRsp(String message, String phoneNumber) {
            this.message = message;
            this.phoneNumber = phoneNumber;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public String getPhoneNumber() {
            return phoneNumber;
        }

        public void setPhoneNumber(String phoneNumber) {
            this.phoneNumber = phoneNumber;
        }
    }

    public static class TencentSmsRsp {
        boolean hasSuccessful;
        long total;
        long failNum;
        String message;
        SendSmsResponse source;

        public TencentSmsRsp() {
        }

        public boolean isHasSuccessful() {
            return hasSuccessful;
        }

        public void setHasSuccessful(boolean hasSuccessful) {
            this.hasSuccessful = hasSuccessful;
        }

        public long getTotal() {
            return total;
        }

        public void setTotal(long total) {
            this.total = total;
        }

        public long getFailNum() {
            return failNum;
        }

        public void setFailNum(long failNum) {
            this.failNum = failNum;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public SendSmsResponse getSource() {
            return source;
        }

        public void setSource(SendSmsResponse source) {
            this.source = source;
        }

        @Override
        public String toString() {
            return "TencentSmsRsp{" + "hasSuccessful=" + hasSuccessful +
                    ", total=" + total +
                    ", failNum=" + failNum +
                    ", message='" + message + '\'' +
                    ", source=" + source +
                    '}';
        }
    }
}
